package drongo.desktop.tools
{
	import drongo.desktop.tools.events.TraceableEvent;
	
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;

	/**
	 * 批量处理 
	 * @author Greg
	 */	
	public class Batch extends EventDispatcher
	{
		private var _itemClass:Class;
		private var _funName:String;
		/**
		 * 是否正在以队列的方式运行 
		 */		
		private var _isQueue:Boolean;
		/**
		 *运行的子项数量 
		 */		
		private var _toolTotal:int;
		/**
		 * 批处理 
		 * @param itemClass			子项类型，注意子项必须是flash.events.EventDispatcher的子类，并且需要派发ToolEvent中的三个事件(error,progres,complete)
		 * @param funName			批量调用子项的那个方法
		 */
		public function Batch(itemClass:Class,funName:String)
		{
			this._itemClass=itemClass;
			this._funName=funName;
		}
		/**
		 * 开始 
		 * @param arguments	批量方法的参数集合
		 * @param isQueue      是否以队列形式执行，false表示同时进行(注意，某些批处理使用非队列会有问题，比如文件写入同一个文件时！)
		 */		
		public function start(arguments:Vector.<Array>,isQueue:Boolean=false):void{
			this._isQueue=isQueue;
			if(this._isQueue){
				_startQueue(arguments);
			}else{
				_startParallel(arguments);
			}
		}
		//===========================================================Queue=================================================================//
		private var _arguments:Vector.<Array>;
		/**
		 *当前完成索引 
		 */		
		private var _toolIndex:int;
		private function _startQueue(arguments:Vector.<Array>):void{
			this._arguments=arguments;
			_toolTotal=this._arguments.length;
			_next();
		}
		private function _next():void{
			var item:EventDispatcher;
			if(_arguments&&_arguments.length>0){
				var itemArguments:Array=_arguments.shift();
				item=new _itemClass();
				item[this._funName](itemArguments)
				TraceableEvent.AddEvents(item,_queueEventHandler);
			}else{
				this.dispatchEvent(new TraceableEvent(TraceableEvent.COMPLETE,"Batch",_itemClass));
			}
		}
		private function _queueEventHandler(e:TraceableEvent):void{
			if(e.type==TraceableEvent.COMPLETE){
				_toolIndex++;
				if(_toolIndex<_toolTotal){
					_next();
				}else{
					this.dispatchEvent(new TraceableEvent(TraceableEvent.COMPLETE,"Batch",_itemClass,0,0,e));
					TraceableEvent.RemoveEvents(e.target as EventDispatcher,_queueEventHandler);
				}
			}else if(e.type==TraceableEvent.PROGRESS){
				this.dispatchEvent(new TraceableEvent(TraceableEvent.PROGRESS,"Batch",_itemClass,_toolIndex,_toolTotal,e));
			}else{
				this.dispatchEvent(new TraceableEvent(TraceableEvent.ERROR,"Batch",_itemClass,0,0,e));
				TraceableEvent.RemoveEvents(e.target as EventDispatcher,_queueEventHandler);
			}
		}
		//===========================================================Parallel=================================================================//
		/**
		 *进度计算帮助字典 
		 */		
		private var _HelpProgressMap:Dictionary;
		private function _startParallel(arguments:Vector.<Array>):void{
			if(!_HelpProgressMap){
				_HelpProgressMap=new Dictionary();
			}
			var len:int=arguments.length;
			var itemArguments:Array;
			var item:EventDispatcher;
			var fun:Function;
			for (var i:int = 0; i < len; i++) 
			{
				itemArguments=arguments[i];
				item=new _itemClass();
				item[this._funName](itemArguments)
				TraceableEvent.AddEvents(item,_parallelEventHandler);
			}
			_toolTotal=len;
		}
		private function _parallelEventHandler(e:TraceableEvent):void{
			var removeEvents:Boolean;
			if(e.type==TraceableEvent.COMPLETE){
				_HelpProgressMap[e.target]=1;
				removeEvents=true;
				if(progress>=_toolTotal){
					_HelpProgressMap=new Dictionary();//清空进度记录
					this.dispatchEvent(new TraceableEvent(TraceableEvent.COMPLETE,"Batch",_itemClass,0,0,e));
				}
			}else if(e.type==TraceableEvent.PROGRESS){
				_HelpProgressMap[e.target]=Number(e.index/e.total);
				var index:Number=isNaN(progress)?0:progress;
				this.dispatchEvent(new TraceableEvent(TraceableEvent.PROGRESS,"Batch",_itemClass,progress,_toolTotal,e));
			}else{
				this.dispatchEvent(new TraceableEvent(TraceableEvent.ERROR,"Batch",_itemClass,0,0,e));
				_HelpProgressMap[e.target]=1;
				removeEvents=true;
				if(progress==_toolTotal){
					_HelpProgressMap=new Dictionary();//清空进度记录
					this.dispatchEvent(new TraceableEvent(TraceableEvent.COMPLETE,"Batch",_itemClass,0,0,e));
				}
			}
			if(removeEvents){
				TraceableEvent.RemoveEvents(e.target as EventDispatcher,_parallelEventHandler);
			}
		}
		private function get progress():Number{
			var results:Number=0;
			for each (var i:Number in _HelpProgressMap) 
			{
				if(!isNaN(i)){
					results+=i;
				}
			}
			return results;
		}
	}
}